'''
Created on Jan 30, 2012

@author: rarakar
'''

import time
import sys
import codecs
import numpy as np
import asjp_util
import multiprocessing as mp
import itertools
import nltk
import re


maxAlternativesStupid=2
useLDND=False
choice=1
alphabet={}
concepts = nltk.defaultdict()
USEMODIFIER = True
MODIFIER_1 = 1
MODIFIER_2 = 2
MODIFIER_3 = 3
codenumber = 0

from asjp_util import cleanRow, invertDict, processASJPWord, merge_1, fileToDM, XXX


def fileToDM(f):
	lists = {}
	lang = "xxx"
	#Discard the first two lines
	f.readline()
	f.readline()
	#the first loop reads concept words
	for row in f:
		items = row.split()
		if not items:
			break
		concepts[items[0]] = items[1]
	#the second loops reads and discards the phonemes
	for row in f:
		if not row.split():
			break
	#the third loop reads language data
	for row in f:
#		print row
		if row[0].isupper():
			index = row.find("{")
			lang = row[0:index]
			#print lang
		elif row[0].isdigit():
			row = row.replace(", ",",")
			row = row.replace("//"," //")
			k = row.find("/")
			if k > -1:
				row = row[:k]
			row = row.replace("(incl.)","")
			row = re.sub("\t{2,}", "\t", row)
			row = row.replace(", ",",")
			items = row.split()
			key = items[0].lstrip("0")
			value = items[1]
			if key in concepts:
				if len(items) < 3:
					print items
				alt = items[2].split(",")
				altlist = []
				for word in alt:
					if word.find('%') == -1 and len(word) > 0:
						altlist.append(processASJPWord(word))
				if lang not in lists: lists[lang] = {}
				if key not in lists[lang]: lists[lang][key] = {}
				lists[lang][key] = altlist
	if 'X' in alphabet:
		global XXX
		codenumber = alphabet['X']
		XXX = [codenumber, codenumber, codenumber]
#	print alphabet
#	print "\n".join(alphabet.iterkeys())
	return lists

def processASJPWord(word):
	"""Processes a ASJP word and converts it into a code string list"""
	word = word.rstrip(" ")
	word = word.lstrip(" ")
	codeword = []
	code = 0
	global codenumber
	if USEMODIFIER is False:
		for ch in word:
			if ch != "~" and ch != "$":
				if alphabet.has_key(ch):
					code = alphabet[ch]
				else:
					code = codenumber
					codenumber += 1
					alphabet[ch] = code
				codeword.append(code)			
	elif USEMODIFIER is True:
		wrdlist = merge_1(word)
		for w in wrdlist:
			if w == '':
				print word, wrdlist
				sys.exit()
			if w in alphabet:
				code = alphabet[w]
			else:
				code = codenumber
				codenumber += 1
				alphabet[w] = code
			codeword.append(code)		
#	print word, codeword
	return codeword

def merge_1(s):
	s=s.replace('\"','%')
#	print s
	s=s.replace('*','&')
#	print s
	sl=list(s)
	for ch in s:
		if ch == '%':
			idx = sl.index('%')
			sl.insert(idx+MODIFIER_1,"".join(sl[idx-MODIFIER_1:idx+MODIFIER_1]))
			del(sl[idx-MODIFIER_1:idx+MODIFIER_1])
		elif ch == '&':
			idx = sl.index('&')
			sl.insert(idx+MODIFIER_1,"".join(sl[idx-MODIFIER_1:idx+MODIFIER_1]))
			del(sl[idx-MODIFIER_1:idx+MODIFIER_1])
		elif ch == '~':
			idx = sl.index('~')
			sl.insert(idx+MODIFIER_1,"".join(sl[idx-MODIFIER_2:idx+MODIFIER_1]))
			del(sl[idx-MODIFIER_2:idx+MODIFIER_1])
		elif ch == '$':
			idx = sl.index('$')
			sl.insert(idx+1,"".join(sl[idx-MODIFIER_3:idx+MODIFIER_1]))
			del(sl[idx-MODIFIER_3:idx+MODIFIER_1])
	return sl

def cleanRow(row):
    row=row.strip("\r\n")
    row=row.replace("\t"," ")
    while row.find("  ")>-1:row=row.replace("  "," ")
    row=row.strip(" ")
    return row

def ldnd(ltuple):
	la = ltuple[1]
	lb = ltuple[2]
	print ltuple[0]
	lv = l = nv = n = 0
	for ka, va in la.iteritems():
		for kb, vb in lb.iteritems():
			if len(va) != 1 or va[0] != XXX:
				if len(vb) != 1 or vb[0] != XXX:
					if ka == kb:
						l = l + 1;lv = lv + ldna(va, vb)
					else:
						n = n + 1;nv = nv + ldna(va, vb)
	if n == 0: return lv / float(l)
	if useLDND:
		return (lv / float(l)) / (nv / float(n))
	else:
		return lv / float(l)

def ldna(aa, bb):
	c = 0
	r = 0
	maxAStupid = maxAlternativesStupid
	for a in aa:
		maxBStupid = maxAlternativesStupid
		for b in bb:
			if maxAStupid > 0 and maxBStupid > 0:
				if choice == 1:
					c = c + 1
					r = r + ldn(a, b)
#				elif choice == 2:
#					c = c + 1
#					r = r + dice(a, b)
#				elif choice == 3:
#					c = c + 1
#					r = r + lcs(a, b)
#				elif choice == 4:
#					c = c + 1
#					r = r + jcd(a, b)
#				elif choice == 5:
#					c = c + 1
#					r = r + prefix(a, b)
#				elif choice == 6:
#					c = c + 1
#					r = r + xdice(a, b)
#				elif choice == 7:
#					c = c + 1
#					r = r + ident(a, b)
#				elif choice == 8:
#					c = c + 1
#					r = r + trigram(a, b)
			maxBStupid = maxBStupid - 1
		maxAStupid = maxAStupid - 1
	if c == 0:
		if choice == 1:
			return 1
		else:
			return 0	
	return r / c

def ldn(a, b):
    m = [];la = len(a) + 1;lb = len(b) + 1
    for i in range(0, la):
        m.append([])
        for j in range(0, lb):m[i].append(0)
        m[i][0] = i
    for i in range(0, lb):m[0][i] = i
    for i in range(1, la):
        for j in range(1, lb):
            s = m[i - 1][j - 1]
            if (a[i - 1] != b[j - 1]):s = s + 1 
            m[i][j] = min(m[i][j - 1] + 1, m[i - 1][j] + 1, s)    
    la = la - 1;lb = lb - 1
    return float(m[la][lb]) / float(max(la, lb))



def computeInterLanguageDistanceMatrix(ls, ilc, sm):
	execThreadCount = mp.cpu_count() * 2
	pool = mp.Pool(execThreadCount)
	chunkSize = 32
	langpairList = list();
	for langpair in itertools.combinations(ilc, r=2):
		print >>sys.stderr, langpair
		langpairList.append((langpair, ls[langpair[0]], ls[langpair[1]]));
#	    langpairList.append((language_distance, langpair, wals_reader, similarityMetric));
	distanceList = pool.imap(ldnd, langpairList, chunkSize);
	for key, distance in zip(langpairList, distanceList):
	    langpair = key[0];
	    lang1 = langpair[0];
	    lang2 = langpair[1];
	 #   INTERLANG_DISTANCE.setdefault(lang1, dict())[lang2] = distance;
	  #  INTERLANG_DISTANCE.setdefault(lang2, dict())[lang1] = distance;
	    print langpair, distance;
    
	
def main():
	start = time.time()
	if len(sys.argv) < 4:
		print >> sys.stderr, "Error: ./ASJP_parallel.py <lang-list> <similarity-metric> <asjp-data-file>."
#		print >> sys.stderr, "Following functionsavailable\n", "\n".join(distances.metricsMap.values());
		sys.exit(1)
	lcFile = sys.argv[1]
	smMetric = sys.argv[2]
	asjpFile = sys.argv[3]
	print asjpFile, smMetric	
#	lcFile = "lcList.txt"
#	smMetric = "cosine"
#	walsDbPath = "wals_data"
	interestedLanguageCodes = [line.strip() for line in codecs.open(lcFile, 'r', 'cp1252')]
	print interestedLanguageCodes
	fin = codecs.open(asjpFile, "r", "cp1252")
	ls = fileToDM(fin)
	print ls['BUSSA_2']
#	print ls['CHIMARIKO']
	
#	print ls
	computeInterLanguageDistanceMatrix(ls, interestedLanguageCodes, smMetric)
	end = time.time()
	print "Time taken %g s" %(end-start)

if __name__ == '__main__':
	main()